"use strict";
/**
 * @ Author: Yoann Meclot. MSay2
 * @ Created on: 2020-08-29 07:59:03
 * @ Modified on: 2020-09-29 10:44:12
 */
/**
 * Copyright (c) 2020 MSay2, Yoann Meclot - @msay2/tspoet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodeWriter = void 0;
const LinkedMap_js_1 = require("../utils/LinkedMap.js");
const StringBuilder_js_1 = require("../utils/StringBuilder.js");
const TSAnnotation_js_1 = require("./TSAnnotation.js");
const TSObject_js_1 = require("./TSObject.js");
const TSPoet_js_1 = require("./TSPoet.js");
class CodeWriter {
    constructor(indents) {
        this.appendable = new StringBuilder_js_1.StringBuilder();
        this.indents = 0;
        if (indents != undefined || indents != null) {
            this.indents = indents;
        }
    }
    emitImports(path, namesClasses) {
        if (!namesClasses.isEmpty()) {
            let nameClassBuilder = new StringBuilder_js_1.StringBuilder();
            for (let name of namesClasses.entries()) {
                nameClassBuilder.append(name.getValue()).append((name.isLastData() ? "" : ", "));
            }
            this.appendable.append(`import { ${nameClassBuilder.toString()} } from "${path}${namesClasses.get(namesClasses.size() - 1)}.js"`)
                .append(CodeWriter.SEMICOLON)
                .append(CodeWriter.NEW_LINE);
        }
    }
    emitStartBlock() {
        this.appendable.append(CodeWriter.NEW_LINE)
            .append(CodeWriter.BEGIN_BRACE)
            .append(CodeWriter.NEW_LINE);
    }
    emitEndBlock() {
        this.removeAllIndents();
        this.appendable.delete(this.appendable.length() - 1);
        this.appendable.append(CodeWriter.NEW_LINE)
            .append(CodeWriter.END_BRACE);
    }
    emitClass(hasModifier) {
        this.appendable.append((hasModifier ? " " : "")).append(TSPoet_js_1.Kind.CLASS);
    }
    emitEnum(hasModifier) {
        this.appendable.append((hasModifier ? " " : "")).append(TSPoet_js_1.Kind.ENUM);
    }
    emitInterface(hasModifier) {
        this.appendable.append((hasModifier ? " " : "")).append(TSPoet_js_1.Kind.INTERFACE);
    }
    emitModifiers(modifiers) {
        if (!modifiers.isEmpty()) {
            for (let entry of modifiers.entries()) {
                this.appendable.append(entry.getValue()).append((entry.isLastData() ? "" : " "));
            }
        }
    }
    emitMethod(method) {
        let annotations = method.annotations;
        let modifiers = method.modifiers;
        let statements = method.statments;
        let parameters = method.parameters;
        let codeBlocks = method.codeBlocks;
        let docs = method.docs;
        let transtypeClasses = method.transtypeClasses;
        let type = method.type;
        let name = method.name;
        this.addIndent();
        this.insertIndentation();
        if (!docs.isEmpty()) {
            this.emitDocs(docs);
        }
        if (!annotations.isEmpty()) {
            for (let entry of annotations.entries()) {
                this.emitAnnotation(entry.getValue());
                this.insertIndentation();
            }
        }
        if (!modifiers.isEmpty()) {
            for (let entry of modifiers.entries()) {
                this.appendable.append(entry.getValue()).append(" ");
            }
        }
        this.appendable.append(name);
        if (!transtypeClasses.isEmpty()) {
            this.appendable.append("<");
            for (let entry of transtypeClasses.entries()) {
                this.appendable.append(entry.getValue()).append((entry.isLastData() ? "" : ", "));
            }
            this.appendable.append(">");
        }
        this.appendable.append("(");
        if (!parameters.isEmpty()) {
            for (let entry of parameters.entries()) {
                let name = entry.getKey();
                let type = entry.getValue();
                this.appendable.append(`${name}:${type.getName()}` + (entry.isLastData() ? "" : ", "));
            }
        }
        this.appendable.append(")");
        if (type != null) {
            this.appendable.append(`:${type.getName()}`);
        }
        this.appendable.append(CodeWriter.BEGIN_BRACE);
        if (!statements.isEmpty()) {
            this.appendable.append(CodeWriter.NEW_LINE);
            this.addIndent();
            this.insertIndentation();
            for (let entry of statements.entries()) {
                this.appendable.append(entry.getValue()).append((entry.isLastData() ? "" : CodeWriter.NEW_LINE));
                if (!entry.isLastData()) {
                    this.insertIndentation();
                }
            }
        }
        if (!codeBlocks.isEmpty()) {
            this.appendable.append(CodeWriter.NEW_LINE);
            this.addIndent();
            this.insertIndentation();
            for (let entry of codeBlocks.entries()) {
                for (let codes of entry.getValue().code.entries()) {
                    let code = codes.getValue();
                    switch (code) {
                        case CodeWriter.BEGIN_BRACE:
                            this.appendable.append(code);
                            this.addIndent();
                            break;
                        case CodeWriter.END_BRACE:
                        case CodeWriter.END_BRACE_SEMICOLON:
                            this.appendable.append(CodeWriter.NEW_LINE);
                            this.removeIndent();
                            this.insertIndentation();
                            this.appendable.append((code == CodeWriter.END_BRACE_SEMICOLON ? `${CodeWriter.END_BRACE}${CodeWriter.SEMICOLON}` : code));
                            if (codes.isLastData() && !entry.isLastData()) {
                                this.appendable.append(CodeWriter.NEW_LINE);
                                this.insertIndentation();
                            }
                            break;
                        default:
                            if (!codes.isFirstData()) {
                                this.appendable.append(CodeWriter.NEW_LINE);
                                this.insertIndentation();
                            }
                            this.appendable.append(code);
                            break;
                    }
                }
            }
        }
        if (!statements.isEmpty() || !codeBlocks.isEmpty()) {
            this.appendable.append(CodeWriter.NEW_LINE);
        }
        this.removeIndent();
        this.insertIndentation();
        this.appendable.append(CodeWriter.END_BRACE);
        this.appendable.append(CodeWriter.NEW_LINE);
    }
    emitAbstractMethod(method) {
        let annotations = method.annotations;
        let modifiers = method.modifiers;
        let parameters = method.parameters;
        let transtypeClasses = method.transtypeClasses;
        let type = method.type;
        let name = method.name;
        this.addIndent();
        this.insertIndentation();
        if (!annotations.isEmpty()) {
            for (let entry of annotations.entries()) {
                this.emitAnnotation(entry.getValue());
                this.insertIndentation();
            }
        }
        if (!modifiers.isEmpty()) {
            for (let entry of modifiers.entries()) {
                this.appendable.append(entry.getValue()).append(" ");
            }
        }
        this.appendable.append(name);
        if (!transtypeClasses.isEmpty()) {
            this.appendable.append("<");
            for (let entry of transtypeClasses.entries()) {
                this.appendable.append(entry.getValue()).append((entry.isLastData() ? "" : ", "));
            }
            this.appendable.append(">");
        }
        this.appendable.append("(");
        if (!parameters.isEmpty()) {
            for (let entry of parameters.entries()) {
                let name = entry.getKey();
                let type = entry.getValue();
                this.appendable.append(`${name}:${type.getName()}` + (entry.isLastData() ? "" : ", "));
            }
        }
        this.appendable.append(")");
        if (type != null) {
            this.appendable.append(`:${type.getName()};`);
        }
        this.appendable.append(CodeWriter.NEW_LINE);
    }
    emitConstants(constants) {
        this.addIndent();
        this.insertIndentation();
        for (let constant of constants.entries()) {
            let tsConstant = constant.getValue();
            let docs = tsConstant.docs;
            if (!docs.isEmpty()) {
                this.emitDocs(tsConstant.docs);
            }
            for (let entry of tsConstant.constants.entries()) {
                let value = entry.getValue();
                this.appendable.append(entry.getKey())
                    .append(" = ")
                    .append((value.constructor.name == "String" ? `\`${value}\`` : value))
                    .append((constant.isLastData() ? "" : ",")).append((constant.isLastData() ? "" : CodeWriter.NEW_LINE));
                this.insertIndentation();
            }
        }
    }
    emitProperties(properties) {
        this.addIndent();
        this.insertIndentation();
        for (let entry of properties.entries()) {
            let property = entry.getValue();
            let name = property.name;
            let parameters = property.parameters;
            let docs = property.docs;
            let typeName = property.typeName;
            if (!docs.isEmpty()) {
                this.emitDocs(docs);
            }
            this.appendable.append(`${name}`);
            if (!parameters.isEmpty()) {
                this.appendable.append("(");
                for (let entry of parameters.entries()) {
                    let name = entry.getKey();
                    let type = entry.getValue();
                    this.appendable.append(`${name}:${type.getName()}` + (entry.isLastData() ? "" : ", "));
                }
                this.appendable.append(")");
            }
            if (typeName != null) {
                this.appendable.append(`:${typeName.getName()};`);
            }
            if (!entry.isLastData()) {
                this.appendable.append(CodeWriter.NEW_LINE);
                this.insertIndentation();
            }
        }
    }
    emitVariable(tsVariable) {
        let name = tsVariable.name;
        let typeName = tsVariable.typeName;
        let value = tsVariable.value;
        let modifiers = tsVariable.modifiers;
        this.addIndent();
        this.insertIndentation();
        if (!modifiers.isEmpty()) {
            for (let entry of modifiers.entries()) {
                this.appendable.append(entry.getValue()).append(" ");
            }
        }
        this.appendable.append(name);
        if (typeName != null) {
            this.appendable.append(`:${typeName.getName()}`);
        }
        if (value != undefined) {
            this.appendable.append(" = ");
            if ((typeof value) == "object") {
                this.appendable.append("{");
                let objectMap = LinkedMap_js_1.LinkedMap.fromObject(value);
                this.addIndent();
                for (let entry of objectMap.entries()) {
                    let key = entry.getKey();
                    let value = entry.getValue();
                    if (value instanceof TSObject_js_1.TSObject) {
                        if (entry.isFirstData()) {
                            this.appendable.append(CodeWriter.NEW_LINE);
                            this.insertIndentation();
                        }
                        this.appendable.append(`${key}: ${value.name}`).append((entry.isLastData() ? "" : ","));
                        this.appendable.append(CodeWriter.NEW_LINE);
                        if (!entry.isLastData()) {
                            this.insertIndentation();
                        }
                    }
                    else if (value.constructor.name == "String") {
                        if (entry.isFirstData()) {
                            this.appendable.append(CodeWriter.NEW_LINE);
                            this.insertIndentation();
                        }
                        this.appendable.append(`${key}: \`${value}\``).append((entry.isLastData() ? "" : ","));
                        this.appendable.append(CodeWriter.NEW_LINE);
                        if (!entry.isLastData()) {
                            this.insertIndentation();
                        }
                    }
                    else {
                        if (entry.isFirstData()) {
                            this.appendable.append(CodeWriter.NEW_LINE);
                            this.insertIndentation();
                        }
                        this.appendable.append(`${key}: ${value}`).append((entry.isLastData() ? "" : ","));
                        this.appendable.append(CodeWriter.NEW_LINE);
                        if (!entry.isLastData()) {
                            this.insertIndentation();
                        }
                    }
                }
                this.removeIndent();
                this.insertIndentation();
                this.appendable.append("}");
            }
            else {
                this.appendable.append((value.constructor.name == "String") ? `\`${value}\`` : value);
            }
        }
        this.appendable.append(CodeWriter.SEMICOLON).append(CodeWriter.NEW_LINE);
    }
    emitAnnotation(tsAnnotation) {
        let name = tsAnnotation.name;
        let values = tsAnnotation.values;
        this.appendable.append("@").append(name);
        if (!values.isEmpty()) {
            this.appendable.append("(");
            for (let entry of values.entries()) {
                let value = entry.getValue();
                if (value.constructor.name == "String") {
                    this.appendable.append((value == TSAnnotation_js_1.TSAnnotation.EMPTY_VALUE ? "" : `\`${value}\``));
                }
                else if ((typeof value) == "object") {
                    this.appendable.append("{");
                    let objectMap = LinkedMap_js_1.LinkedMap.fromObject(value);
                    this.addIndent();
                    for (let entry of objectMap.entries()) {
                        let key = entry.getKey();
                        let value = entry.getValue();
                        if (value instanceof TSObject_js_1.TSObject) {
                            if (entry.isFirstData()) {
                                this.appendable.append(CodeWriter.NEW_LINE);
                                this.insertIndentation();
                            }
                            this.appendable.append(`${key}: ${value.name}`).append((entry.isLastData() ? "" : ","));
                            this.appendable.append(CodeWriter.NEW_LINE);
                            if (!entry.isLastData()) {
                                this.insertIndentation();
                            }
                        }
                        else if (value.constructor.name == "String") {
                            if (entry.isFirstData()) {
                                this.appendable.append(CodeWriter.NEW_LINE);
                                this.insertIndentation();
                            }
                            this.appendable.append(`${key}: \`${value}\``).append((entry.isLastData() ? "" : ","));
                            this.appendable.append(CodeWriter.NEW_LINE);
                            if (!entry.isLastData()) {
                                this.insertIndentation();
                            }
                        }
                        else {
                            if (entry.isFirstData()) {
                                this.appendable.append(CodeWriter.NEW_LINE);
                                this.insertIndentation();
                            }
                            this.appendable.append(`${key}: ${value}`).append((entry.isLastData() ? "" : ","));
                            this.appendable.append(CodeWriter.NEW_LINE);
                            if (!entry.isLastData()) {
                                this.insertIndentation();
                            }
                        }
                    }
                    this.removeIndent();
                    this.insertIndentation();
                    this.appendable.append("}");
                }
                this.appendable.append((!entry.isLastData() ? ", " : ""));
            }
            this.appendable.append(")");
        }
        this.appendable.append(CodeWriter.NEW_LINE);
    }
    emitDocs(docs) {
        this.appendable.append("/**").append(CodeWriter.NEW_LINE);
        for (let entry of docs.entries()) {
            this.insertIndentation();
            this.appendable.append(" * ").append(entry.getValue()).append(CodeWriter.NEW_LINE);
        }
        this.insertIndentation();
        this.appendable.append(" */").append(CodeWriter.NEW_LINE);
        this.insertIndentation();
    }
    emitComments(comments) {
        for (let entry of comments.entries()) {
            this.insertIndentation();
            this.appendable.append("// ").append(entry.getValue()).append(CodeWriter.NEW_LINE);
        }
    }
    emit(arg) {
        this.appendable.append(arg);
        return this;
    }
    emitToStart(arg) {
        this.appendable.appendAt(0, arg);
    }
    toString() {
        return this.appendable.toString();
    }
    addIndent() {
        this.indents += 1;
    }
    removeIndent() {
        this.indents -= 1;
    }
    removeAllIndents() {
        this.indents = 0;
    }
    insertIndentation() {
        let numIndent = this.indents;
        for (let i = 0; i < numIndent; i++) {
            this.appendable.append(CodeWriter.TAB);
        }
    }
}
exports.CodeWriter = CodeWriter;
CodeWriter.BEGIN_BRACE = "{";
CodeWriter.END_BRACE = "}";
CodeWriter.SEMICOLON = ";";
CodeWriter.NEW_LINE = "\n";
CodeWriter.TAB = "\t";
CodeWriter.END_BRACE_SEMICOLON = "ms:_endBraceForSemicolon_";
//# sourceMappingURL=CodeWriter.js.map